/*
Copyright (C) 2022-2024 Inspur Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/
package main

import (
	"encoding/json"
	"fmt"
	"ichain/contract/stub"
	pb "ichain/protos/inode"
)

type DidContract struct {
}

const (
	DidInfoPrefix          = "DID_"
	IssuerInfoPrefix       = "ISS_"
	CptInfoPrefix          = "CPT_"
	CredentialInfoPrefix   = "CRE_"
	PresentationInfoPrefix = "PRE_"

	FuncSaveDidInfo          = "saveDidInfo"
	FuncGetDidInfo           = "getDidInfo"
	FuncSaveIssuerInfo       = "saveIssuerInfo"
	FuncGetIssuerInfo        = "getIssuerInfo"
	FuncSaveCptInfo          = "saveCptInfo"
	FuncGetCptInfo           = "getCptInfo"
	FuncSaveCredentialInfo   = "saveCredentialInfo"
	FuncGetCredentialInfo    = "getCredentialInfo"
	FuncSavePresentationInfo = "savePresentationInfo"
	FuncGetPresentationInfo  = "getPresentationInfo"
)

type DidInfo struct {
	Did             string `json:"did"`
	WalletId        string `json:"walletId"`
	Version         string `json:"version"`
	Authentication  string `json:"authentication"`
	Recovery        string `json:"recovery"`
	ResolveEndpoint string `json:"resolveEndpoint"`
	ProofSignature  string `json:"proofSignature"`
}

type IssuerInfo struct {
	Id          string `json:"id"`
	Did         string `json:"did"`
	Name        string `json:"name"`
	ServiceType string `json:"serviceType"`
	Endpoint    string `json:"endpoint"`
}

type CptInfo struct {
	Id        string      `json:"id"`
	Title     string      `json:"title"`
	IssuerId  string      `json:"issuerId"`
	IssuerDid string      `json:"issuerDid"`
	Claims    []ClaimInfo `json:"claims"`
}

type ClaimInfo struct {
	Property    string `json:"property"`
	ValueType   string `json:"valueType"`
	Description string `json:"description"`
}

type CredentialInfo struct {
	Id        string `json:"id"`
	IssuerDid string `json:"issuerDid"`
	CptId     string `json:"CptId"`
	OwnerDid  string `json:"ownerDid"`
	ClaimHash string `json:"claimHash"`
}

type PresentationInfo struct {
	Id           string `json:"id"`
	CredentialId string `json:"credentialId"`
	Challenge    string `json:"challenge"`
	Domain       string `json:"domain"`
	Signature    string `json:"signature"`
}

type Result struct {
	Success bool        `json:"success"`
	Msg     string      `json:"msg"`
	Data    interface{} `json:"data,omitempty"`
}

func (t *DidContract) Init(stubif stub.ContractStub) pb.Response {
	return stub.Success(nil)
}

func (t *DidContract) Invoke(stubif stub.ContractStub) pb.Response {
	fn, args := stubif.GetFunctionAndParameters()
	var result string

	switch fn {
	case FuncSaveDidInfo:
		result = saveDidInfo(stubif, args)
	case FuncGetDidInfo:
		result = getDidInfo(stubif, args)
	case FuncSaveIssuerInfo:
		result = saveIssuerInfo(stubif, args)
	case FuncGetIssuerInfo:
		result = getIssuerInfo(stubif, args)
	case FuncSaveCptInfo:
		result = saveCptInfo(stubif, args)
	case FuncGetCptInfo:
		result = getCptInfo(stubif, args)
	case FuncSaveCredentialInfo:
		result = saveCredentialInfo(stubif, args)
	case FuncGetCredentialInfo:
		result = getCredentialInfo(stubif, args)
	case FuncSavePresentationInfo:
		result = savePresentationInfo(stubif, args)
	case FuncGetPresentationInfo:
		result = getPresentationInfo(stubif, args)
	default:
		result = getResult(false, "参数错误，方法不存在")
	}

	return stub.Success([]byte(result))
}

func saveDidInfo(stubif stub.ContractStub, args []string) string {
	if len(args) != 2 {
		return getResult(false, "参数数量错误")
	}
	key := DidInfoPrefix + args[0]
	value := []byte(args[1])
	var didInfo DidInfo
	err := json.Unmarshal(value, &didInfo)
	if err != nil {
		return getResult(false, "DID信息格式错误")
	}
	err = stubif.PutState(key, value)
	if err != nil {
		return getResult(false, "DID信息格式错误")
	}
	return getResult(true, "上链成功")
}

func getDidInfo(stubif stub.ContractStub, args []string) string {
	if len(args) != 1 {
		return getResult(false, "参数数量错误")
	}
	key := DidInfoPrefix + args[0]
	bytes, err := stubif.GetState(key)
	if err != nil {
		return getResult(false, "读取链上数据失败")
	}
	if bytes == nil {
		return getResult(false, "DID不存在")
	}
	var didInfo DidInfo
	json.Unmarshal(bytes, &didInfo)
	return getResult(true, "获取成功", didInfo)
}

func saveIssuerInfo(stubif stub.ContractStub, args []string) string {
	if len(args) != 2 {
		return getResult(false, "参数数量错误")
	}
	key := IssuerInfoPrefix + args[0]
	value := []byte(args[1])
	var issuerInfo IssuerInfo
	err := json.Unmarshal(value, &issuerInfo)
	if err != nil {
		return getResult(false, "发证方信息格式错误")
	}
	err = stubif.PutState(key, value)
	if err != nil {
		return getResult(false, "发证方信息格式错误")
	}
	return getResult(true, "上链成功")
}

func getIssuerInfo(stubif stub.ContractStub, args []string) string {
	if len(args) != 1 {
		return getResult(false, "参数数量错误")
	}
	key := IssuerInfoPrefix + args[0]
	bytes, err := stubif.GetState(key)
	if err != nil {
		return getResult(false, "读取链上数据失败")
	}
	if bytes == nil {
		return getResult(false, "发证方不存在")
	}
	var issuerInfo IssuerInfo
	json.Unmarshal(bytes, &issuerInfo)
	return getResult(true, "获取成功", issuerInfo)
}

func saveCptInfo(stubif stub.ContractStub, args []string) string {
	if len(args) != 2 {
		return getResult(false, "参数数量错误")
	}
	key := CptInfoPrefix + args[0]
	value := []byte(args[1])
	var cptInfo CptInfo
	err := json.Unmarshal(value, &cptInfo)
	if err != nil {
		return getResult(false, "cpt信息格式错误")
	}
	err = stubif.PutState(key, value)
	if err != nil {
		return getResult(false, "cpt信息格式错误")
	}
	return getResult(true, "上链成功")
}

func getCptInfo(stubif stub.ContractStub, args []string) string {
	if len(args) != 1 {
		return getResult(false, "参数数量错误")
	}
	key := CptInfoPrefix + args[0]
	bytes, err := stubif.GetState(key)
	if err != nil {
		return getResult(false, "读取链上数据失败")
	}
	if bytes == nil {
		return getResult(false, "cpt不存在")
	}
	var cptInfo CptInfo
	json.Unmarshal(bytes, &cptInfo)
	return getResult(true, "获取成功", cptInfo)
}

func saveCredentialInfo(stubif stub.ContractStub, args []string) string {
	if len(args) != 2 {
		return getResult(false, "参数数量错误")
	}
	key := CredentialInfoPrefix + args[0]
	value := []byte(args[1])
	var credentialInfo CredentialInfo
	err := json.Unmarshal(value, &credentialInfo)
	if err != nil {
		return getResult(false, "凭证信息格式错误")
	}
	err = stubif.PutState(key, value)
	if err != nil {
		return getResult(false, "凭证信息格式错误")
	}
	return getResult(true, "上链成功")
}

func getCredentialInfo(stubif stub.ContractStub, args []string) string {
	if len(args) != 1 {
		return getResult(false, "参数数量错误")
	}
	key := CredentialInfoPrefix + args[0]
	bytes, err := stubif.GetState(key)
	if err != nil {
		return getResult(false, "读取链上数据失败")
	}
	if bytes == nil {
		return getResult(false, "凭证不存在")
	}
	var credentialInfo CredentialInfo
	json.Unmarshal(bytes, &credentialInfo)
	return getResult(true, "获取成功", credentialInfo)
}

func savePresentationInfo(stubif stub.ContractStub, args []string) string {
	if len(args) != 2 {
		return getResult(false, "参数数量错误")
	}
	key := PresentationInfoPrefix + args[0]
	value := []byte(args[1])
	var presentationInfo PresentationInfo
	err := json.Unmarshal(value, &presentationInfo)
	if err != nil {
		return getResult(false, "vp信息格式错误")
	}
	err = stubif.PutState(key, value)
	if err != nil {
		return getResult(false, "vp信息格式错误")
	}
	return getResult(true, "上链成功")
}

func getPresentationInfo(stubif stub.ContractStub, args []string) string {
	if len(args) != 1 {
		return getResult(false, "参数数量错误")
	}
	key := PresentationInfoPrefix + args[0]
	bytes, err := stubif.GetState(key)
	if err != nil {
		return getResult(false, "读取链上数据失败")
	}
	if bytes == nil {
		return getResult(false, "vp不存在")
	}
	var presentationInfo PresentationInfo
	json.Unmarshal(bytes, &presentationInfo)
	return getResult(true, "获取成功", presentationInfo)
}

func getResult(success bool, msg string, data ...interface{}) string {
	result := Result{success, msg, nil}
	if len(data) >= 1 {
		result.Data = data[0]
	}
	bytes, _ := json.Marshal(result)
	return string(bytes)
}

func main() {
	if err := stub.Start(new(DidContract)); err != nil {
		fmt.Printf("Error starting DidContract: %s", err)
	}
}
